/*
 * DevicesIIC.c
 *
 *      Author: Honrun
 */
#include "gd32l23x.h"
#include "stdio.h"
#include "DevicesDelay.h"
#include "DevicesIIC.h"


#define IIC_SPEED_VALUE     100000
#define IIC_DELAY_TIME      ((1000000.0f / IIC_SPEED_VALUE) + 1.0f)


void vIIC0Init(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C0);

    /* configure GPIO pins of I2C1 */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_6);

    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_7);

    i2c_deinit(I2C0);
    /* configure I2C timing */
    i2c_timing_config(I2C0, 0x0, 0x3, 0);
    i2c_master_clock_config(I2C0, 0x13, 0x36);
    /* configure I2C address */
    i2c_address_config(I2C0, 0x00, I2C_ADDFORMAT_7BITS);
    /* enable I2C automatic end mode in master mode */
    i2c_automatic_end_enable(I2C0);
    /* enable I2C0 */
    i2c_enable(I2C0);
}

/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC0DeInit(void)
{
    int8_t i = 0;

    gpio_bit_set(GPIOB, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7);

    vDelayUs(100);

    /* 发送9个时钟脉冲，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        vDelayUs(5);
        gpio_bit_reset(GPIOB, GPIO_PIN_6);
        vDelayUs(5);
        gpio_bit_reset(GPIOB, GPIO_PIN_7);
        vDelayUs(5);
        gpio_bit_set(GPIOB, GPIO_PIN_6);
        vDelayUs(5);
        gpio_bit_set(GPIOB, GPIO_PIN_7);
    }

    vIIC0Init();
}

/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC1DeInit(void)
{
}

int8_t cI2CxWriteDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, void* pvDatas, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = vIIC0DeInit;
    uint8_t *pucDatas = pvDatas;
    uint32_t timeout = 0, startCnt = 0;

    if((iLength < 1) || (pvDatas == NULL))
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
    {
        if(timeout >= I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }

        vDelayUs(IIC_DELAY_TIME);
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt <= I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        /* configure slave address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
        /* configure number of bytes to be transferred */
        i2c_transfer_byte_number_config(i2c_periph, iLength + 1);
        /* clear I2C_TDATA register */
        I2C_STAT(i2c_periph) |= I2C_STAT_TBE;
        /* disable I2C automatic end mode in master mode */
        i2c_automatic_end_enable(i2c_periph);

        i2c_start_on_bus(i2c_periph);

        /* wait until the transmit data buffer is empty */
        for(timeout = 0; (timeout < I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TBE) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send address */
        i2c_data_transmit(i2c_periph, usRegAddr);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TI) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        if(timeout < I2C_BYTE_WRITE_TIME_OUT)
            break;
    }

    while((iLength--) > 0)
    {
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TBE) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send data */
        i2c_data_transmit(i2c_periph, *pucDatas++);
    }

    /* wait until the byte transmission finishes */
    for(timeout = 0; (timeout < (I2C_BYTE_WRITE_TIME_OUT * 2)) && (i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* clear STPDET flag */
    i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

    return 0;
}

int8_t cI2CxReadDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, void* pvDatas, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = vIIC0DeInit;
    uint8_t *pucDatas = pvDatas;
    uint32_t timeout = 0, startCnt = 0;

    if((iLength < 1) || (pvDatas == NULL))
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; (timeout <= I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET); ++timeout)
    {
        if(timeout >= I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }

        vDelayUs(IIC_DELAY_TIME);
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt <= I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        /* clear I2C_TDATA register */
        I2C_STAT(i2c_periph) |= I2C_STAT_TBE;
        /* configure slave address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
        /* configure number of bytes to be transferred */
        i2c_transfer_byte_number_config(i2c_periph, 1);
        /* disable I2C automatic end mode in master mode */
        i2c_automatic_end_disable(i2c_periph);

        i2c_start_on_bus(i2c_periph);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; (timeout < I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TBE) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send address */
        i2c_data_transmit(i2c_periph, usRegAddr);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TC) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        if(timeout < I2C_BYTE_WRITE_TIME_OUT)
            break;
    }

    /* configure one byte address */
    i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_RECEIVE);
    /* configure number of bytes to be transferred */
    i2c_transfer_byte_number_config(i2c_periph, iLength);
    /* enable I2C automatic end mode in master mode */
    i2c_automatic_end_enable(i2c_periph);

    /* restart */
    i2c_start_on_bus(i2c_periph);
    /* wait until the transmit data buffer is empty */
    for(timeout = 0; (timeout < I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    while((--iLength) > 0)
    {
        /* wait until the RBNE bit is set */
        for(timeout = 0; (timeout < I2C_BYTE_READ_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_RBNE) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* read data */
        *pucDatas++ = i2c_data_receive(i2c_periph);
    }

    /* wait until the byte transmission finishes */
    for(timeout = 0; (timeout < (I2C_BYTE_WRITE_TIME_OUT * 2)) && (i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* clear STPDET flag */
    i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

    return 0;
}
